/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       handler.h

	$Header: /game/handler.h $

	$NoKeywords: $

 ************************************************************************/

#ifndef ADAPTOR_HANDLER_H_INCLUDED
#define ADAPTOR_HANDLER_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "handler.h"

// -------------------------------------------------------------------
// class to adapt a single-argument function to a zero-argument handler
// -------------------------------------------------------------------
template <class type>
class t_add_handler : public t_handler_base
{
public:
	typedef t_handler_base_1<type> t_function;

	t_add_handler( t_function* function, type arg ) : m_function( function ), 
		                                              m_argument( arg )
	{
	}

	virtual void operator()()
	{
		m_function( m_argument );
	}
protected:
	type              m_argument;
	t_handler_1<type> m_function;
};

// -------------------------------------------------------------------
// class to adapt a 2-argument function to a 1-argument callback handler.
// Passes argument as 1st arg in adapted function.
// -------------------------------------------------------------------
template <class type_1, class type_2>
class t_add_1st_handler_1 : public t_handler_base_1<type_2>
{
public:
	typedef t_handler_base_2<type_1, type_2> t_function;

	t_add_1st_handler_1( t_function* function, type_1 arg ) 
		               : m_function( function ), m_argument( arg )
	{
	}

	virtual void operator()( type_2 arg )
	{
		m_function( m_argument, arg );
	}
protected:
	type_1                      m_argument;
	t_handler_2<type_1, type_2> m_function;
};

// -------------------------------------------------------------------
// class to adapt a 2-argument function to a 1-argument callback handler.
// Passes argument as 2nd arg in adapted function.
// -------------------------------------------------------------------
template <class type_1, class type_2>
class t_add_2nd_handler_1 : public t_handler_base_1<type_1>
{
public:
	t_add_2nd_handler_1( t_handler_base_2<type_1, type_2>* function, type_2 arg ) 
		               : m_function( function ), m_argument( arg )
	{
	}

	virtual void operator()( type_1 arg )
	{
		m_function( arg, m_argument );
	}
protected:
	type_2                      m_argument;
	t_handler_2<type_1, type_2> m_function;
};

// -------------------------------------------------------------------
// class to adapt a 3-argument function to a 2-argument callback handler.
// Passes argument as 1st arg in adapted function.
// -------------------------------------------------------------------
template <class type_1, class type_2, class type_3>
class t_add_1st_handler_2 : public t_handler_base_2<type_2,type_3>
{
public:
	t_add_1st_handler_2( t_handler_base_3<type_1, type_2, type_3>* function, type_1 arg ) 
		               : m_function( function ), m_argument( arg )
	{
	}

	virtual void operator()( type_2 arg_2, type_3 arg_3 )
	{
		m_function( m_argument, arg_2, arg_3 );
	}
protected:
	type_1                              m_argument;
	t_handler_3<type_1, type_2, type_3> m_function;
};

// -------------------------------------------------------------------
// class to adapt a 3-argument function to a 2-argument callback handler.
// Passes argument as 2nd arg in adapted function.
// -------------------------------------------------------------------
template <class type_1, class type_2, class type_3>
class t_add_2nd_handler_2 : public t_handler_base_2<type_1,type_3>
{
public:
	t_add_2nd_handler_2( t_handler_base_3<type_1, type_2, type_3>* function, type_2 arg ) 
		               : m_function( function ), m_argument( arg )
	{
	}

	virtual void operator()( type_1 arg_1, type_3 arg_3 )
	{
		m_function( arg_1, m_argument, arg_3 );
	}
protected:
	type_2                              m_argument;
	t_handler_3<type_1, type_2, type_3> m_function;
};
 
// -------------------------------------------------------------------
// class to adapt a 3-argument function to a 2-argument callback handler.
// Passes argument as 3rd arg in adapted function.
// -------------------------------------------------------------------
template <class type_1, class type_2, class type_3>
class t_add_3rd_handler_2 : public t_handler_base_2<type_1,type_2>
{
public:
	t_add_3rd_handler_2( t_handler_base_3<type_1, type_2, type_3>* function, type_3 arg ) 
		               : m_function( function ), m_argument( arg )
	{
	}

	virtual void operator()( type_1 arg_1, type_2 arg_2 )
	{
		m_function( arg_1, arg_2, m_argument );
	}
protected:
	type_3                              m_argument;
	t_handler_3<type_1, type_2, type_3> m_function;
};

// -------------------------------------------------------------------
// class to adapt a zero-argument function to a 1-argument handler 
// -------------------------------------------------------------------
template <class type>
class t_discard_handler_1 : public t_handler_base_1<type>
{
public:
	t_discard_handler_1( t_handler_base* function ) : m_function( function )
	{
	}

	virtual void operator()( type arg )
	{
		m_function();
	}
protected:
	t_handler m_function;
};

// -------------------------------------------------------------------
// class to adapt a 1-argument function to a 2-argument handler, discarding
// the 1st argument
// -------------------------------------------------------------------
template <class type_1, class type_2>
class t_discard_1st_handler_2 : public t_handler_base_2<type_1, type_2>
{
public:
	t_discard_1st_handler_2( t_handler_base_1<type_2>* function ) : m_function( function )
	{
	}

	virtual void operator()( type_1 arg_1, type_2 arg_2 )
	{
		m_function( arg_2 );
	}
protected:
	t_handler_1<type_2> m_function;
};

// -------------------------------------------------------------------
// class to adapt a 1-argument function to a 2-argument handler, discarding
// the 1st argument
// -------------------------------------------------------------------
template <class type_1, class type_2>
class t_discard_2nd_handler_2 : public t_handler_base_2<type_1, type_2>
{
public:
	t_discard_2nd_handler_2( t_handler_base_1<type_1>* function ) : m_function( function )
	{
	}

	virtual void operator()( type_1 arg_1, type_2 arg_2 )
	{
		m_function( arg_1 );
	}
protected:
	t_handler_1<type_1> m_function;
};

// -------------------------------------------------------------------
// class to adapt a 1-argument function to a 2-argument handler, discarding
// the 1st argument
// -------------------------------------------------------------------
template <class type_1, class type_2, class type_3>
class t_discard_1st_handler_3 : public t_handler_base_3<type_1, type_2, type_3>
{
public:
	t_discard_1st_handler_3( t_handler_base_2<type_2, type_3>* function ) : m_function( function )
	{
	}

	virtual void operator()( type_1 arg_1, type_2 arg_2, type_3 arg_3 )
	{
		m_function( arg_2, arg_3 );
	}
protected:
	t_handler_2<type_2, type_3> m_function;
};

// -------------------------------------------------------------------
// class to adapt a 2-argument function to a 3-argument handler, discarding
// the 2nd argument
// -------------------------------------------------------------------
template <class type_1, class type_2, class type_3>
class t_discard_2nd_handler_3 : public t_handler_base_3<type_1, type_2, type_3>
{
public:
	t_discard_2nd_handler_3( t_handler_base_2<type_1, type_3>* function ) : m_function( function )
	{
	}

	virtual void operator()( type_1 arg_1, type_2 arg_2, type_3 arg_3 )
	{
		m_function( arg_1, arg_3 );
	}
protected:
	t_handler_2<type_1, type_3> m_function;
};

// -------------------------------------------------------------------
// class to adapt a 2-argument function to a 3-argument handler, discarding
// the 3rd argument
// -------------------------------------------------------------------
template <class type_1, class type_2, class type_3>
class t_discard_3rd_handler_3 : public t_handler_base_3<type_1, type_2, type_3>
{
public:
	t_discard_3rd_handler_3( t_handler_base_2<type_1, type_2>* function ) : m_function( function )
	{
	}

	virtual void operator()( type_1 arg_1, type_2 arg_2, type_3 arg_3 )
	{
		m_function( arg_1, arg_2 );
	}
protected:
	t_handler_2<type_1, type_2> m_function;
};

// convenience functions
// 
// typical usage:
//
// t_client
// {
// public:
//     void click_1( t_button*, int result );
//     void click_2();
//     void click_3( int result );
//	
// 
// button->set_handler( add_2nd_argument( bound_handler( *this, &t_client::click_1), value ) ) );
//
// button->set_handler( discard_argument<t_button*>( bound_handler( *this, &t_client::click_2 ) ) );
// 
// button->set_handler( discard_argument<t_button*>( 
//                      add_argument( bound_handler( *this, &t_client::click_3 ), value ) ) );

template <class type>
inline t_handler add_argument( t_handler_base_1<type>* function, type arg )
{
	return new t_add_handler<type>( function, arg );
}

template <class type>
inline t_handler add_argument( t_handler_1<type> function, type arg )
{
	return new t_add_handler<type>( function, arg );
}

template <class type_1, class type_2>
inline t_handler_1<type_2> add_1st_argument( t_handler_base_2<type_1,type_2>* function,
											 type_1 arg )
{
	return new t_add_1st_handler_1<type_1,type_2>( function, arg );
}

template <class type_1, class type_2>
inline t_handler_1<type_2> add_1st_argument( t_handler_2<type_1,type_2> function,
											 type_1 arg )
{
	return new t_add_1st_handler_1<type_1,type_2>( function, arg );
}

template <class type_2, class type_1>
inline t_handler_1<type_1> add_2nd_argument( t_handler_base_2<type_1, type_2>* function, 
										     type_2 arg ) 
{
	return new t_add_2nd_handler_1<type_1, type_2>( function, arg );
}

template <class type_2, class type_1>
inline t_handler_1<type_1> add_2nd_argument( t_handler_2<type_1, type_2> function, 
										     type_2 arg ) 
{
	return new t_add_2nd_handler_1<type_1, type_2>( function, arg );
}              
                 
template <class type_1, class type_2, class type_3>
inline t_handler_2<type_2,type_3> 
       add_1st_argument( t_handler_base_3<type_1, type_2, type_3>* function, type_1 arg ) 
{
	return new t_add_1st_handler_2<type_1,type_2,type_3>( function, arg );
}

template <class type_1, class type_2, class type_3>
inline t_handler_2<type_2,type_3> 
       add_1st_argument( t_handler_3<type_1, type_2, type_3> function, type_1 arg ) 
{
	return new t_add_1st_handler_2<type_1,type_2,type_3>( function, arg );
}

template <class type_2, class type_1, class type_3>
inline t_handler_2<type_1, type_3>
	   add_2nd_argument( t_handler_base_3<type_1, type_2, type_3>* function, type_2 arg )
{
	return new t_add_2nd_handler_2<type_1,type_2,type_3>( function, arg );
}

template <class type_2, class type_1, class type_3>
inline t_handler_2<type_1, type_3>
	   add_2nd_argument( t_handler_3<type_1, type_2, type_3> function, type_2 arg )
{
	return new t_add_2nd_handler_2<type_1,type_2,type_3>( function, arg );
}

template <class type_3, class type_1, class type_2>
inline t_handler_2<type_1,type_2>
       add_3rd_argument( t_handler_base_3<type_1, type_2, type_3>* function, type_3 arg )
{
	return new t_add_3rd_handler_2<type_1,type_2,type_3>( function, arg );
}

template <class type_3, class type_1, class type_2>
inline t_handler_2<type_1,type_2>
       add_3rd_argument( t_handler_3<type_1, type_2, type_3> function, type_3 arg )
{
	return new t_add_3rd_handler_2<type_1,type_2,type_3>( function, arg );
}

template <class type>
inline t_handler_1<type> discard_argument( t_handler_base* function )
{
	return new t_discard_handler_1<type>( function );
}

template <class type_1, class type_2>
inline t_handler_2<type_1, type_2> discard_1st_argument( t_handler_base_1<type_2>* function )
{
	return new t_discard_1st_handler_2<type_1,type_2>( function );
}

template <class type_2, class type_1>
inline t_handler_2<type_1,type_2> discard_2nd_argument( t_handler_base_1<type_1>* function )
{
	return new t_discard_2nd_handler_2<type_1,type_2>( function );
}

template <class type_1, class type_2, class type_3>
inline t_handler_3<type_1,type_2, type_3> 
       discard_1st_argument( t_handler_base_2<type_2,type_3>* function )
{
	return new t_discard_1st_handler_3( function );
}

template <class type_2, class type_1, class type_3>
inline t_handler_3<type_1,type_2,type_3>
       discard_2nd_argument( t_handler_base_2<type_1, type_3>* function )
{
	return new t_discard_2nd_handler_3<type_1,type_2,type_3>( function );
}

template <class type_3, class type_1, class type_2>
inline t_handler_3<type_1,type_2,type_3>
	   discard_3rd_argument( t_handler_base_2<type_1, type_2>* function )
{
	return new t_discard_3rd_handler_3<type_1,type_2,type_3>( function );
}

#endif // ADAPTOR_HANDLER_H_INCLUDED